#include <zenilib.h>
#include "Player.h"
#include "BrainSlug.h"
#include "Person.h"
#include "Globals.h"

using namespace std;

Player::Player(Vector2 pos)
{
	playertype = HUMAN;
	body = new BrainSlug(pos);
	controlsPerson = false;
	InitializeControls(pos);
	brain = NULL;
	this->jumpVelocity = -550.0f;
	walkVelocity = 300.0f;
	playerCanSee = true;
}

void Player::setWeaponType(WeaponType type_)
{
	type = type_;
	if (controlsPerson && playertype != ENEMY && playertype != BOSS){
		switch (type){
			case UZI:
				body->setColorFilter(0, "red");
				break;
			case LASER:
				body->setColorFilter(0, "yellow");
				break;
			case SHURIKEN:
				body->setColorFilter(0, "black");
				break;
			case BIGGUN:
				body->setColorFilter(0, "orange");
				break;
		}
	}
}

void Player::InitializeControls(Vector2 pos)
{
	int t = rand() % 7;
	if (t < 6){
		setWeaponType((WeaponType)((int)(t / 2)));
	}
	else{
		setWeaponType(BIGGUN);
	}
	timeToPerformAction = 0.0f;
	timeElapsedPerformingAction = 0.0f;
	timeSinceLastShot = 2.0f;
	timeSinceLastDamage = 0.0f;

	previousPosition = pos;
	jumpTarget = NULL;
	weapon = NULL;
	gone = false;
	attackTime = 0;
}

Player::~Player()
{
	delete body;
}

void Player::render()
{
	body->render();
	if (weapon){
		weapon->render();
	}
	body->renderExtras();
	float x = body->left();
	float y = body->top() - 7;
	float maxWidth = body->right() - x;
	float height = 5;
	if (body->getTexture(1) == "Boss1Attack"){
		x += 12.5;
		maxWidth -= 25;
	}
	else if (body->getTexture(1) == "Boss1Jump"){
		x = body->getPos().x - 25;
		maxWidth = 50;
		y = body->getPos().y - 50;
	}
	if (brain){
		brain->render();
	}
	std::string color = "red";
	float dh;
	if (controlsPerson && playertype != CIVILIAN){
		y -= 15;
		if (playertype == HUMAN){
			dh = (float)brain->hostHealth / (float)brain->maxHostHealth;
			Zeni::render_image("HealthBar", Zeni::Point2f(x, y - height - 2), Zeni::Point2f(x + maxWidth * dh, y - 2), 0, 1.0f, Zeni::Point2f(x, y), false, Zeni::get_Colors()["green"]);
		}
	}
	else if (playertype == HUMAN){
		color = "green";
	}
	dh = (float)body->hostHealth / (float)body->maxHostHealth;
	Zeni::render_image("HealthBar", Zeni::Point2f(x, y), Zeni::Point2f(x + maxWidth * dh, y + height), 0, 1.0f, Zeni::Point2f(x, y), false, Zeni::get_Colors()[color]);
}

void Player::update(const float &timestep)
{
	if(playerCanSee)
	{
		previousPosition = getPos();
		//adjust movement
		float speed = this->walkVelocity;
		if (jumpTarget){
			Vector2 seperation = jumpTarget->brainSlugPos() - getPos();
			if (seperation.length2() < body->getRadius()){
				jumpTarget->gone = true;
				jumpOn(jumpTarget);
				jumpTarget = NULL;
			}
			else{
				body->setVel(2 * speed * seperation.normal());
			}
		}
		else{
			Vector2 vel = body->getVel();
			if (controls.left && !controls.right){
				vel.x = -speed;
				body->moving = true;
				body->setFlipped(true);
			}
			else if (controls.right && !controls.left){
				vel.x = speed;
				body->moving = true;
				body->setFlipped(false);
			}
			else{
				body->moving = false;
				vel.x = 0;
			}
			if (controls.jump){
				controls.jump = false;
				if (body->grounded()){
					body->platform = NULL;
					body->moving = true;

					if (controlsPerson)
						jumpVelocity = -600.0f;
					else
						jumpVelocity = -750.0f;
					vel.y = jumpVelocity;
				}
			}
			body->setVel(vel);
		}
		body->update(timestep);
		if (dead()){
			weapon = NULL;
		}
		if (body->gone){
			gone = true;
		}
		if (weapon){
			weapon->update(timestep);
		}
		body->checkPlatform();
	}
}

bool Player::canJumpOnPlatform(GameObject* p) 
{
	float maxHeightTime = -this->jumpVelocity / this->body->getAccel().y;
	float maxJumpHeightPos = body->getAccel().y * maxHeightTime * maxHeightTime / 2 +
													 jumpVelocity * maxHeightTime + getPos().y;
	return((maxJumpHeightPos + this->body->getScale().y / 2) < 
		     (p->getPos().y - p->getScale().y / 2));
}

void Player::handlePlatformCollision(GameObject* p, float dt)
{
	Collision c(body, p, dt);
	if (c.m_collisionReported){
		Vector2 vel = body->getVel();
		c.applyResponse(dt);
		if (vel.y > 0 && c.m_ncoll.y < -sqrt_two / 2){
			body->platform = p;
		}
	}
}

void Player::handlePlayerCollision(Player* p, float dt)
{
	Collision c(body, p->body, dt);
	if (c.m_collisionReported)
	{
		if (this->playertype == HUMAN && p->playertype == BOSS && this->timeSinceLastDamage > 2.5f){
			if (p->getBody()->getTexture(1) == "Boss1Attack"){
				this->body->hostHealth -= 20;
				this->timeSinceLastDamage = 0.0f;
				return;
			}
			else if (p->getBody()->getTexture(1) == "Boss1Jump"){
				this->body->hostHealth -= 10;
				this->timeSinceLastDamage = 0.0f;
				return;
			}
		}
		// Stomping Damage
		if (this->getPos().y > p->getPos().y + p->body->getScale().y/4 && p->body->grounded()){
			if (!controlsPerson && this->playertype == HUMAN && this->timeSinceLastDamage > 2.5f)
			{
				if (p->playertype == BOSS){
					this->body->hostHealth -= 20;
				}
				else{
					this->body->hostHealth -= 10;
				}
				this->timeSinceLastDamage = 0.0f;
			}
		}
	}
}

bool Player::handleHealthPackCollsion(HealthPack* hp)
{
	if(this->playertype == HUMAN && Collision::objectsIntersect(body, hp))
	{
		if(this->controlsPerson)
		{
			if(this->brain->hostHealth == this->brain->maxHostHealth &&
				 this->body->hostHealth == this->body->maxHostHealth)
				 return false;

			this->brain->hostHealth += hp->healthAmount;
			if(this->brain->hostHealth > this->brain->maxHostHealth)
			{
				int extra = this->brain->hostHealth - this->brain->maxHostHealth;
				this->brain->hostHealth = this->brain->maxHostHealth;
				this->body->hostHealth += extra;
				if(this->body->hostHealth > this->body->maxHostHealth)
					this->body->hostHealth = this->body->maxHostHealth;
			}
		}
		else
		{
			if(this->body->hostHealth == this->body->maxHostHealth)
				return false;
			this->body->hostHealth += hp->healthAmount;
			if(this->body->hostHealth > this->body->maxHostHealth)
				this->body->hostHealth = this->body->maxHostHealth;
		}
		return true;
	}
	return false;
}

bool Player::handleProjectileCollision(Projectile* p)
{
	if (p->getFiredBy() != this){
		if (Collision::objectsIntersect(body, p)){
			if(this->playertype == HUMAN && this->timeSinceLastDamage > 2.5f)
			{
				if(this->body->hostHealth > 0)
					this->body->hostHealth -= p->damage;
				else
					this->brain->hostHealth -= p->damage;
			}
			else if(this->timeSinceLastDamage > 2.5f)
			{
				if(p->getFiredBy()->playertype == HUMAN)
					this->body->hostHealth -= p->damage * 2.0f;
				else
					this->body->hostHealth -= p->damage;
			}
			else {}

			if (p->getWeaponType() != LASER){
				return true;
			}
			else if(this->timeSinceLastDamage > 2.5f){
				this->timeSinceLastDamage = 2.25f;
				return true;
			}
			else {}
		}
	}
	return false;
}

float Player::distanceFrom(Player *p)
{
	return body->distanceFrom(p->body);
}

Vector2 Player::brainSlugPos()
{
	Vector2 p = -Vector2(body->getFlipped() ? -12 : 12, body->getRadius() - 7);
	if (body->getTextureNum() == 1 || body->getTextureNum() == 3){
		p += Vector2(body->getFlipped() ? -0.5f : 0.5f, 0.5f);
	}
	if (body->getTexture(1) == "Boss1Jump"){
		p = p.rotate(-body->getRot() + (body->getFlipped() ? -pi / 4 : pi / 4));
	}
	else if (body->getTexture(1) == "Boss1Attack"){
		p = p.rotate(-body->getRot() + (body->getFlipped() ? -pi / 4 : pi / 4));
	}
	else{
		p = p.rotate(-body->getRot());
	}
	p += getPos(); 
	return p;
}

void Player::setExtrasInPosition()
{
	if (brain){
		brain->setPos(brainSlugPos());
		float rot = body->getRot() + (body->getFlipped() ? -pi / 4 : pi / 4);
		if (body->getTexture(1) == "Boss1Jump" || body->getTexture(1) == "Boss1Attack"){
			rot -= body->getFlipped() ? -pi / 4 : pi / 4;
		}
		brain->setRot(rot);
	}
	if (weapon){
		weapon->setPos(weaponPos());
		weapon->setFlipped(body->getFlipped());
	}
}

Vector2 Player::weaponPos()
{
	Vector2 pos;
	switch (type){
		case LASER:
			pos = Vector2(body->getFlipped() ? body->left() - 25 : body->right() + 23, body->getPos().y - 21);
			break;
		case BIGGUN:
			pos = Vector2(body->getFlipped() ? body->left() - 10 : body->right() + 8, body->getPos().y - 36);
			break;
		default:
			pos = Vector2(body->getFlipped() ? body->left() - 19 : body->right() + 17, body->getPos().y - 22);
			break;
	}
	if (playertype == ENEMY){
		pos += Vector2(body->getFlipped() ? 4 : -5, 1);
	}
	return pos;
}

void Player::jumpOn(Player* p)
{
	brain = body;
	brain->setTexture(0, "BrainSlug1");
	body = new Person(p->body->getPos());
	body->hostHealth = p->body->hostHealth;
	body->maxHostHealth = p->body->maxHostHealth;
	controlsPerson = true;
	if (playertype == HUMAN){
		body->setTexture(0, "PersonWeaponStillShirt");
		body->setTexture(1, "PersonWeaponStill");
		body->preTexture = "PersonWeapon";
	}
	else if (playertype == ENEMY){
		body->setTexture(0, "");
		body->setTexture(1, "AgentStill");
		body->preTexture = "Agent";
	}
	setWeaponType(p->type);
	weapon = new Weapon(type, this);
}

SpriteObject* Player::jumpOff()
{
	SpriteObject *oldBody = body;
	body = brain;
	brain = NULL;
	body->setVel(Vector2(0, -350.0f));
	body->setRot(0);
	oldBody->setTexture(0, "PersonStillShirt");
	oldBody->setTexture(1, "PersonStill");
	oldBody->preTexture = "Person";
	controlsPerson = false;
	body->platform = NULL;
	weapon = NULL;
	return oldBody;
}

vector<Projectile*> Player::fireWeapon()
{
	if (weapon){
		return weapon->fireProjectile();
	}
	vector<Projectile*> empty;
	return empty;
}
